package ufrj.safcp.modules.autenticacao;

import java.awt.Dimension;
import java.awt.Image;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ufrj.safcp.controller.BaseController;
import ufrj.safcp.controller.State;
import ufrj.safcp.tools.fingerprint.GriauleFingerprintHandler;
import ufrj.safcp.tools.fingerprint.IFingerprintHandler;
import ufrj.safcp.tools.fingerprint.IFingerprintReceiver;
import ufrj.safcp.tools.imagecapturing.IImageCapturing;
import ufrj.safcp.tools.imagecapturing.LTICivilImageCapturing;
import ufrj.safcp.tools.qrcode.IQRCodeHandler;
import ufrj.safcp.tools.qrcode.UnredableCodeException;
import ufrj.safcp.tools.qrcode.ZXingQRCodeHandler;
import ufrj.safcp.util.ConversionUtil;


public class AutenticacaoController extends BaseController {
	
	static {
		new Thread(new Runnable() {
			public void run() {
				// fazendo isso apenas para mostrar o splash da griaule no início.
				GriauleFingerprintHandler.getInstance();
			}
		}, "Iniciador Griaule").start();
	}
	
	private static Logger logger = LoggerFactory.getLogger(AutenticacaoController.class);
	
	private static final int SEGUNDOS_TENTANDO_LER_QRCODE = 30;

	private IFingerprintHandler fingerprintHandler;
	
	private byte[] templateLido;

	private IQRCodeHandler qrCodeHandler;
	
	private IImageCapturing imageCapturing;
	
	private Integer cardNumber;
	
	private Integer fiscalNumber;
	
	private boolean parecer;

	public State AUTENTICANDO_FISCAL = new State(1, "Autenticando Fiscal") {

		@Override
		public void enterState() {
			fingerprintHandler = GriauleFingerprintHandler.getInstance();
			fingerprintHandler.init(25, new IFingerprintReceiver() {
				
				@Override
				public void receiveFingerprint(Image fingerprint, byte[] templateData, String templateString) {
					// TODO: verificar agente
					/*
					for (int i = 0; i < templatesFiscal.length; i++) {
						fingerprintHandler.match(templateData, templatesFiscal[i]);
					}
					*/
					fiscalNumber = 12345;
					getFrame().reportLeituraDigitalDoFiscal(1, true, fingerprint, "Carlos Siqueira Gomes");
					try {
						Thread.sleep(2000);
					} catch (Exception e) {
						// do nothing
					}
					changeState(AUTENTICANDO_FISCAL, AGUARDANDO_CANDIDATO);
				}
			});
			fingerprintHandler.start();
			
		}

		@Override
		public void exitState() {
			//fingerprintHandler.stop();
			fingerprintHandler.destroy();
			fingerprintHandler = null;
		}
		
	};
	
	public State AGUARDANDO_CANDIDATO = new State(2, "Aguardando candidato") {

		public void enterState() {
			resetAllVariables();
		};
		

		public void exitState() {
			
		};
		
	};
	
	public State COLETANDO_QRCODE = new State(3, "Coletando QRCode") {
		public void enterState() {
			
			imageCapturing = LTICivilImageCapturing.getInstance();
			
			imageCapturing.init(0, new Dimension(800, 600));
			imageCapturing.start();
			imageCapturing.addImageReceiver(getFrame().getCameraPanel());
			
			qrCodeHandler = ZXingQRCodeHandler.getInstance();
			
			//TODO Ler QRCOde
		};
		public void exitState() {
			imageCapturing.stop();
			imageCapturing = null;
			
			qrCodeHandler = null;
		};
	};
	
	public State COLETANDO_DIGITAIS = new State(4, "Coletando digital") {
		
		private int nLeituras;
		
		public void enterState() {
			
			nLeituras = 0;
			
			fingerprintHandler = GriauleFingerprintHandler.getInstance();
			fingerprintHandler.init(25, new IFingerprintReceiver() {
				

				@Override
				public void receiveFingerprint(Image fingerprint, byte[] templateData, String templateString) {
					
					boolean match;
					try {
						match = fingerprintHandler.match(templateData, templateLido);
					} catch (IllegalStateException e) {
						getFrame().showError("Erro ao conferir digital, QRCode lido pode ter sido adulterado.");
						match = false;
					}
					getFrame().reportLeituraDigitalDoCandidato(3, match, fingerprint);
					
					if (match) {
						new Thread(new Runnable() {
							public void run() {
								try {
									Thread.sleep(100);
								} catch (InterruptedException e) {
								}
								parecer = true;
								changeState(COLETANDO_DIGITAIS, PARECER_AUTENTICACAO);
							}
						}).start();
					} else {
						nLeituras++;
						if (nLeituras == 3) {
							parecer = false;
							changeState(COLETANDO_DIGITAIS, PARECER_AUTENTICACAO);
						}
					}
					
				}
			});
		};
		
		public void exitState() {
			fingerprintHandler.destroy();
			fingerprintHandler = null;
		};
	};
	
	public State PARECER_AUTENTICACAO = new State(5, "Parecer Autenticação") {

		public void enterState() {
			getFrame().reportParecerFinal(parecer);
		};
		
		public void exitState() {
		
		};
	};

	
	@Override
	public State[] getAllStates() {
		return new State[]{AUTENTICANDO_FISCAL, AGUARDANDO_CANDIDATO, COLETANDO_QRCODE, COLETANDO_DIGITAIS, PARECER_AUTENTICACAO};
	}
	
	public AutenticacaoController() {
		mainFrame = new AutenticacaoMainFrame(this);
	}
	
	protected AutenticacaoMainFrame getFrame() {
		return ((AutenticacaoMainFrame)mainFrame);
	}

	@Override
	public void start() {
		super.start();
		changeState(null, AUTENTICANDO_FISCAL);
	}
	
	private void resetAllVariables() {
		
		// Apagando cartão
		getFrame().clearQRCodeInfo();
		cardNumber = null;
		
		// Apagando template digital
		getFrame().clearDigital();
	}
	

	public void prossegueParaColetas() {
		changeState(AGUARDANDO_CANDIDATO, COLETANDO_QRCODE);
	}
	

	public void leQRCode() {

		long startTime = System.currentTimeMillis();
		
		getFrame().clearQRCodeInfo();
		cardNumber = null;
		
		int nTentativas = 0;
		
		while (true) {
			
			if (System.currentTimeMillis() - startTime >= SEGUNDOS_TENTANDO_LER_QRCODE * 1000) break;
			
			try {
				nTentativas++;
				
				byte[] decode = qrCodeHandler.decode(imageCapturing.getLastCapturedImage());
				
				byte[] cardNumberByte = new byte[4];
				
				byte[] template = new byte[decode.length - 4 - 4];
				
				for (int i = 0; i < 4; i++) {
					cardNumberByte[i] = decode[i];
				}
				
				for (int i = 8; i < decode.length; i++) {
					template[i-8] = decode[i];
				}
				
				cardNumber = ConversionUtil.convertBytesToInt(cardNumberByte);
				
				templateLido = template;
				
				break;
				
			} catch (UnredableCodeException e) {
				logger.debug(e.getMessage());
				try {
					Thread.sleep(10);
				} catch (InterruptedException e1) {
				}
			}
		}
		
		logger.debug("Numero de tentativas: " + nTentativas + ", sucesso: " + (cardNumber != null));
		if (cardNumber != null) {
			getFrame().reportQRCodeRead(cardNumber, 7);
		} else {
			getFrame().reportQRCodeReadError("Erro ao ler QRCode.");
		}
		
	}
	
	public void colherDigitais() {
		
		changeState(COLETANDO_QRCODE, COLETANDO_DIGITAIS);
		
		fingerprintHandler.start();
		fingerprintHandler.startEnroll();
	}

	public void reiniciar() {
		changeState(PARECER_AUTENTICACAO, AGUARDANDO_CANDIDATO);
	}


}
